05. 웹에서 가속을 이끌어 내는 방법
📝 Contents
웹 브라우저 동작 이해하기
- 사용자가 입력창에 접속하고자 하는 웹 사이트 주소를 입력함으로써 브라우저의 동작이 시작됨
- 브라우저는 가장 먼저 도메인 서버와 통신하여 접속하려는 호스트의 IP를 찾음
- 그리고 해당 아이피를 가진 서버와 통신을 시도해 TCP 연결을 맺음
- HTTPS에선 암호화된 연결을 생성하려는 협의 단계가 더 추가됨
- 이후 연결이 맺어지면 브라우저는 서버로부터 필요한 리소스들을 다운로드해 이를 화면에 표시함
- 브라우저가 리소스를 다운로드할 때는 먼저 방문 페이지의 HTML을 서버에 요청해 다운로드함
- 그리고 HTML의 구문을 분석하면서 HTML 태그에 참조된 CSS, 자바스크립트, 이미지, 폰트 등의 하위 리소스들을 차례로 다운로드함
- 이렇게 화면을 그리는 일련의 작업 절차를 렌더링 경로라고 함
브라우저 아키텍처
브라우저는 크게 7개 컴포넌트로 나눌 수 있음
유저 인터페이스
- 브라우저 엔진
- 렌더링 엔진
- 네트워킹
- UI 백엔드
- 자바스크립트 해석기
데이터 저장소
사용자 요청을 처리하고 웹 사이트를 표현하기 위해 모든 컴포넌트들이 유기적으로 동작함
- 실제로 HTML을 처리해 화면에 렌더링하는 컴포넌트는 렌더링 엔진임
중요 렌더링 경로
- 브라우저는 HTML을 가장 처음 구문 분석하면서 DOM 트리를 만들고 CSS를 구문 분석하여 CSSOM 트리를 만듬
- 그 후 두 개의 트리 모델을 결합해 최종적으로 렌더 트리를 만듬
- 일단 렌더 트리가 생성되면 브라우저는 이를 기반으로 페이지 구조를 결정하고 화면에 표현함
DOM 트리 생성
- 브라우저는 가장 먼저 다운로드한 HTML의 구문을 분석해 태그를 하나하나 해석하여 DOM이라는 객체 모델로 변환함
- DOM은 객체 지향적 프로그램 언어들로 마크업 문서들을 손쉽게 프로그래밍하기 위해 표준으로 규정한 프로그램 인터페이스
- DOM은 다른 프로그래밍 인터페이스와 마찬가지로 객체 속성과 메소드 그리고 이벤트 등의 정의함
- 브라우저 구문 분석기는 위에서부터 순차적으로 HTML을 분석하며 부모 노드와 자식 노드와의 관계를 파악해 DOM 트리를 생성함
CSSOM 트리 생성
- CSS를 처리하기 위한 트리 구조의 프로그래밍 인터페이스
- 브라우저가 HTML을 구문 분석하며 CSS를 참조하는 링크를 만나면 해당 CSS 리소스를 다운로드하고 구문 분석기가 CSS를 분석하기 시작함
- HTML과 다르게 CSS는 구문 분석에는 엄격한 구문 검사가 적용되고, 구문 분석 방법이 다르다 보니 사용하는 구문 분석기와 동작 스레드도 다름
- 따라서 HTML 구문 분석 과정이 CSS 분석에 의해 방해받진 않음
- 렌더링 경로상에서 DOM 트리와 CSSOM 트리는 각각 별도로 생성되고 이후 렌더 트리로 통합됨
- CSS는 페이지 스타일 정보를 나타내므로 CSSOM 트리의 각 노드들은 고유한 스타일 속성을 포함함
렌더 트리 생성
- DOM 트리와 CSSOM 트리 구문 분석이 완료되면 브라우저는 두 개의 트리를 병합해 렌더 트리를 생성함
- DOM과 CSSOM을 기반으로 렌더링을 위한 최종 정보를 가진 렌더 객체들을 생성해 이들의 상하 관계를 트리 모양으로 구성한 것이 렌더 트리임
- CSSOM 트리에서
display:none
으로 설정되어 있으면 렌더 트리에서 제외됨
레이아웃
- 렌더 트리 노드들의 위치 정보가 계산되는 단계
- 렌더 객체는 사각형 영역을 표시하므로 브라우저 창의 맨 왼쪽 위에서 시작하여 아래, 오른쪽으로 이동하며 각 사각형 영역의 너비와 높이를 계산함
- 렌더 트리의 루트 노드부터 계산 시작
- 루트 노드의 너비는 뷰포트의 크기로 지정되고, 바로 아래인 자식 노드들의 너비가 비율로 되어 있으면 이 뷰포트 너비에서 각 자식 노드들의 너비가 계산
- 높이 계산은 역으로 자식 노드의 높이에 따라 부모 노드의 높이를 계산
- 이 작업들은 재귀적으로 반복 수행됨
페인트
- 렌더 트리 정보를 바탕으로 브라우저 창에 표현하는 단계
- 렌더링을 위한 정보가 모두 준비되었으므로 GPU를 이용해 그리기만 하면 됨
- DOM과 CSSOM을 동적으로 변경할 수 있고, 이 경우 렌더 트리가 변경되고 레이아웃, 페인트 단계가 다시 수행됨
브라우저 렌더링 최적화하기
DOM 최적화하기
- HTML은 잘못된 습관이나 실수에 의해 문법 오류가 발생해도 브라우저에는 정상적으로 표현되는 경우가 많음
- 다양한 오류를 포용하기 위해 브라우저는 잘 알려진 수많은 오류 사항에 대한 예외 처리 방안을 구현함
- 웹 페이지 내에 오류가 많을수록 브라우저는 예외 처리를 위해 더 많은 메모리와 CPU 파워를 소모함
- HTML의 구문 오류를 최소화하고 간소화하는 것이 웹 사이트 성능을 향상시키는 기본적이고도 간단한 방법임
- 과도하게 HTML 태그를 중첩 사용하는 행위도 피해야 함
- 태그가 중첩되어 HTML 문서 구조가 복잡하게 작성되어 있으면, 자바스크립트에 의해 스타일이 변경될 때 각 태그의 레이아웃을 다시 계산하고 재구성하는 데 더 많은 리소스와 시간이 소요됨
- 일반적으로 중첩된 태그들이 15단계를 넘지 않도록 HTML을 작성하는 것을 권장함
- DOM을 분석해 최적화 방안을 알려주는 무료 도구인 DOM Monster가 있음
자바스크립트와 CSS 배치하기
- HTML 구문 분석기가 순차적으로 HTML을 해석하는 중 자바스크립트를 만나면 이를 다운로드하고 수행이 완료될 때까지 DOM 생성 작업을 중단함
- 자바스크립트에 의한 변경이 완료되기를 기다리는 것
- 이 시점에 특정 CSS에 대한 구문 분석 처리 및 CSSOM 생성 작업이 진행 중이라면 자바스크립트가 변경하려는 스타일 시트가 아직 생성되지 않았을 수 있음
- 그러므로 해당 자바스크립트는 CSSOM 생성이 완료될 때까지 수행을 중지하고 대기함
- 원하는 스타일 시트가 채 생성되기도 전에 자바스크립트가 이를 수정하려는 경우 스크립트 오류가 발생해 만들고자 하는 웹 페이지가 생성되지 않음
- 렌더링에 있어 CSS가 자바스크립트보다 더 높은 우선순위를 갖고, 두 리소스 모두 전체 렌더링 과정을 지연시킬 수 있는 중요한 렌더링 방해 리소스임
- 이러한 CSS와 자바스크립트의 렌더링 방해를 피하려면 CSS를 최대한 소스 위쪽에 배치하여 CSSOM이 가능한 빨리 생성되도록 해야함
- 자바스크립트는 최대한 HTML 아래쪽에 배치하여 DOM과 CSSOM이 모두 생성된 이후에 수행될 수 있도록 하는 것이 가장 효과적임
자바스크립트 최적화하기
- 자바스크립트를 HTML 아래쪽에 배치하는 것만으로도 렌더링의 방해 요소가 많이 사라지지만 이는 충분하지 않음
- 최근의 웹 페이지는 타사 제공 리소스를 포함한 많은 수의 자바스크립트를 사용하고, HTML의 위쪽에 배치해야 하는 경우도 부지기수이기 때문
- 자바스크립트가 전체 페이지 로딩 시간에 영향을 주는 것을 막으려면 자바스크립트 수행이 렌더링 스레드를 방해하지 않도록 별도 스레드로 자바스크립트를 수행시켜야 함
- 또는 렌더링 작업이 어느 정도 끝난 이후 스크립트를 수행해야 함
- 이때 자바스크립트에서 제공하는 관련 속성을 활용할 수 있음
- async 속성: HTML 구문 분석과 동시에 자바스크립트를 다운로드하고 수행되도록 함
<script src="async_script.js" async></script>
- defer 속성: 구문 분석 중에 별도의 스레드로 자바스크립트를 다운로드하고 구문 분석이 끝난 이후에 수행되도록 함
<script src="defer_script.js" defer></script>
- async 속성은 지연 수행 시 스크립트 간 선후 관계를 따지지 않지만 defer 속성은 스크립트가 호출된 순서에 따라 차례로 수행됨
- 모든 자바스크립트가 비동기나 지연 처리의 대상이 될 수 없음
- 자바스크립트들은 많은 경우 렌더링에 관여하도록 구현됨
- 또한 스크립트 사이에 종속 관계가 있을 수 있으므로 비동기 처리나 지연 처리를 무분별하게 적용하면 안됨
- 따라서 초기 렌더링에 꼭 필요한 그룹과 그렇지 않은 그룹으로 분류해 후자의 그룹에 async, defer 속성을 적용해야 함
- 더 확실한 방법은 브라우저가 페이지 로딩을 명시적으로 끝낸 후 나머지 스크립트를 수행시키는 방법임
- onload 이벤트 이후에 스크립트 수행
CSS 최적화하기
- CSS는 필요한 정보만 빠르게 다운로드하고 실행해야 브라우저 렌더링을 가속시킬 수 있음
- 이를 위해 첫 번쨰로 CSS를 적절히 분리하여 필요한 페이지에 필요한 CSS 파일만 포함해야 함
- 두 번째로는 첫 화면에 사용될 CSS 파일과 숨겨진 화면에 사용될 CSS 파일을 분리해 후자의 CSS는 지연 수행시켜야 함
- 필요한 CSS만 다운로드하려면 미디어 쿼리를 활용할 수 있음
- 미디어 쿼리의 조건과 함께 해당하는 CSS 파일을 링크시키면 조건에 맞지 않는 파일은 다운로드하지 않음
- 숨겨질 화면에 적용될 CSS 파일들은 아래 예처럼 onLoad 이벤트 발생 이후 적용되도록 처리함
이미지 로딩 최적화하기
- CSS에 의해 이미지가 숨겨질 것을 미리 알고 있다면 브라우저가 그 이미지를 다운로드하지 않음으로써 페이지 로딩을 더 가속화 할 수 있음
- 하지만 DOM과 CSSOM이 별도 분석되고 생성되기 떄문에 브라우저는 이를 미리 알지 못하고 DOM 트리에 나타난 객체들을 모두 다운로드함
- 화면 렌더링에 필요하지 않은 이미지를 다운로드하지 않기 위한 3가지 방법이 있음
- 첫 번째로 만약 그 이미지가 웹 사이트의 주요 이미지가 아니라면 CSS의 background-image 속성을 사용해 원하지 않는 다운로드를 피할 수 있음
- 브라우저가 CSS를 분석할 때 숨겨질 이미지는 미리 알고 다운로드하지 않기 때문임
- 두 번째로 자바스크립트를 이용한 지연 로딩 방식을 적용해 불필요한 다운로드를 피함
- 지연 로딩이 브라우저 로딩 속도 개선에 효과적일 수 있으나 사용자 경험 개선에 항상 도움이 되지 않음
- 모든 이미지에 지연 로딩을 적용하면 브라우저의 프리로더가 이미지를 다운로드할 수없으므로 오히려 성능을 저해하는 요소가 됨
- 따라서 지연로딩은 첫 화면에 등장하지 않거나 숨겨진 이미지들을 다운로드하는데만 사용해야 함
- 세 번째로 Progressive JPG를 활용할 수 있음
- Progressive JPG는 고품질 이미지를 한 번에 전송하지 않고 분할 전송하는 방식으로 브라우저에서는 초기에 저품질 이미지가 보이지만 점차 원래 품질을 회복함
도메인 분할 기법 이용하기
- 여러 도메인을 소유한 경우 웹 콘텐츠를 병렬적으로 동시에 다운로드할 수 있도록 하는 방법
- 브라우저는 HTTP/1.1 프로토콜 하에서 동일 도메인에 순차적 다운로드 방식을 사용
- 도메인 분할은 HTTP/1.1 프로토콜 하에서 브라우저의 제약을 피하는 방식
- 브라우저는 동일 호스트명의 동시 연결 개수를 제한하고 있는데, 한 도메인당 6~13개의 TCP 연결들을 동시에 생성해 여러 리소스를 한 번에 다운로드할 수 있도록 허용함
- 따라서 6개의 동시 연결을 지원하는 브라우저에서(크롬) 도메인 분할 방식을 통해 2개의 도메인을 이용하면 이론적으로는 12개의 연결이 가능함
- 콘텐츠의 특징에 따라 도메인을 나누어 병렬로 동시 다운로드한다면 전반적인 다운로드 완료 시간을 앞당겨짐
- 도메인 분할 기법을 이용하면 사이트 전체의 쿠키 사이지를 축소할 수 있는 장점도 있음
- 웹 사이트의 개인화가 심화될 수록 쿠키에는 더 많은 정보가 저장되고 크키도 점점 커짐
- 도메인을 여러 개로 분할하는 방법은 기술적으로 크게 어렵지 않지만, 도메인을 몇 개로 운영하는 것이 최적인지 결정하는 데는 면밀한 계획과 테스트가 필요함
- 너무 많은 도메인을 추가하면 오히려 브라우저 성능을 저하시킬 수 있으므로 주의해야 함
- 동시 다운로드가 숫자가 많아질수록 브라우저는 더 많은 CPU 리소스를 사용하고 CPU 리소스가 한계에 도달하면 오히려 다운로드 속도를 느리게 만들기 때문임
- 또한 브라우저는 각 도메인에 대한 DNS 조회를 수행하고 TCP 연결을 생성하며 생성된 도메인에 대한 연결을 유지해야 하므로 이는 결국 페이지 로딩 속도를 현저히 떨어뜨림
- 결론적으로 최신 컴퓨터의 CPU 파워 및 네트워크 속도를 감안할 때 리소스 숫자에 따라 도메인 수를 결정하는 것이 바람직함
- 도메인 개수가 정해지면 그 수에 맞도록 리소스들을 균등 분할하는 것을 권함
- 특정 도메인에서 대부분의 리소스를 다운로드한다면 다른 도메인들은 오히려 TCP 연결을 위한 리소스만 낭비하게 되므로 차라리 없애는 것을 추천함
- 리소스 분류 방법은 리소스 성격 또는 동적으로 분류하는 두 가지 방법이 있음
- 리소스 성격에 따른 분류: 자바스크립트, CSS, 폰트 같은 다양한 렌더링, 이미지, 멀티미디어 리소스들을 종류별로 구분하고 그 수를 파악해 도메인별로 균등하게 분배되도록 그룹화하는 방법
- 보다 정확한 분배를 위해서는 리소스 성격에 따라 분류하기보다 배포 시점에 동적으로 도메인명 결정하는 것을 권함
- 이때 특정 리소스에 항상 같은 도메인이 배정되도록해야만 캐시 적중률이 높아짐
- 특정 리소스에 동일한 도메인을 배정하는 방안 중 하나로 해시 방식을 사용할 수 있음
- 해시 방식이란 해시 함수를 사용해 파일명을 숫자 배열로 변경하고 숫자에 따라 도메인을 결정하는 방식
도메인 분할 기법과 HTTP/2
- 도메인 분할 기법이 고안된 이유는 HTTP/1.1의 가장 큰 문제점으로 지적되어 온 Head Of Line Blocking 현상 때문임
- 이 문제점은 HTTP/2의 멀티플렉싱 기술로 해결되어 도메인 분할 기법을 사용할 이유도 자연스럽게 사라짐
- 이 기법을 사용하면 오히려 HTTP/2만의 특징인 헤더 압축 전송, 우선순위 전송 그리고 서버 푸시 기능을 방해하므로 사용하지 않는 것을 추천함
- 하지만 예전 버전의 브라우저들은 아직 HTTP/2를 지원하지 않기 때문에 아직은 여러 개의 도메인이 필요할 수 있음
- 최근 사용되는 브라우저들은 HTTP/2의 기능을 저해하지 않으면서 다중 도메인을 사용할 수 있는 TCP 연결을 병합하는 방식을 제공함
- 연결 병합은 브라우저가 첫 번째 도메인과 맺은 TCP 연결을 나머지 도메인에 재사용하는 방식
- 이 기술이 적용되기 위해서는 두 가지 고려해야 할 사항이 있음
- 첫 번째로 브라우저가 DNS를 확인할 때 각 도메인은 모두 동일한 IP 주소를 반환해야 함
- 두 번째로 동일한 인증서를 사용해야 함
사용자 경험 개선하기
- 브라우저 성능 지표만 향상 시킨다고 해서 실제 사용자가 느끼는 성능이 향샹되는 것은 아님
- 이를 위해 다른 방식의 측정 방법 및 개선 방안이 요구됨
사용자 경험 지표 바로 알기
- 사용자 중심 지표에는 먼저 WebPageTest의 Speed Index가 사용됨
- Speed Index는 시간에 따른 웹 사이트의 시각적 진행 상태를 수치화한 지표
- 값이 작을수록 시각적 진행 상태가 빠르다는 것을 의미
- 이 외에도 구글 크롬 팀을 주축으로 다양한 사용자 중심 성능 지표가 개발되고 있음
- 화면에 눈에 띄는 콘텐츠가 처음 표현되는 시점인 첫 번째 콘텐츠가 있는 페인트
- 히어로 이미지와 같은 주요 콘텐츠가 로딩되는 시점인 가장 큰 콘텐츠가 있는 페인트
- 사용자와 상호 작용이 어느 정도 가능해지는 시점인 상호 작용 시간
- 구글 W3C 컨소시엄이 제시한 사용자 경험의 단계에 따른 주요 지표는 책의 [표 5-2] 참고
사용자 요청에 빠르게 반응하기
- 사용자 요청에 빠르게 반응하려면 기본적으로 서버의 응답이 빨라야 함
- 브라우저가 서버에서 응답한 첫 번째 바이트를 수신하는 시간을 Time To First Byte(TTFB)라고 하는데 일반적으로 300~500ms가 이상적임
- 이를 위해서는 HTML 내의 주석이나 공백 등 불필요한 코드들을 모두 제거하여 전송되는 바이트 크기를 줄여야 함
- 또한 HTML 페이지를 캐시하여 서버 처리 시간을 최소화하는 것을 권함
브라우저가 렌더링을 빠르게 시작하게 하려면 다음과 같은 최적화 기법들을 고려할 수 있음
CSS와 자바스크립트 파일들의 크기를 줄임
- CSS와 자바스크립트들을 중요 리소스와 그렇지 않은 리소스로 분류함
- 위에서 분류된 중요 리소스들은 가능한 빠르게 로딩시킴
- preload나 HTTP/2 서버 푸시 활용
- 중요하지 않은 리소스들은 나중에 로딩시킴
- async나 defer 속성을 사용하거나 onLoad 이벤트 이후에 수행하도록 지연시킬 수 있음
사용자 시선 붙잡기
- 브라우저가 화면 렌더링을 시작했더라도 2초 안에 의미 있는 콘텐츠가 표현되지 않으면 사용자가 사이트를 이탈할 가능성이 높음
- 사용자가 이탈하지 않도록 시선을 붙잡으려면 Hero 이미지가 가능한 빠르게 화면에 로딩되어야 함
- Hero 이미지가 늦게 로딩되는 주된 이유는 페이지 로딩 시간을 개선하기 위해 모든 이미지들을 일괄적으로 지연 로딩시키기 때문임
- 일반적으로 브라우저의 프리로더 스레드가 메인 스레드와는 별도로 페이지 내의 리소스들을 미리 다운로드할 수 있음
- 지연 로딩이 적용된 이미지들은 이 프리로더 대상에 포함되지 않음
- 따라서 이미지 지연 로딩은 Hero 이미지들을 제외한 나머지 이미지들에 적용해야 함
- Hero 이미지가 늦게 로딩되는 또다른 이유는 CSS의 background-image 속성으로 지정되었을 경우
<img>
태그로 지정된 이미지들은 HTML 구문 분석과 함께 다운로드되지만, CSS background-imgae 속성으로 지정된 이미지들은 CSS가 분석되고 DOM에 적용될 때 다운로드되고, 프리로더에도 적용되지 않음
결론적으로 아래 구칙을 따르면 Hero 이미지를 일찍 로딩하여 사용자 경험을 향상시킬 수 있음
HTML의
<img>
태그나<picture>
태그를 사용하여 직접 다운로드하고 지연 로딩을 적용하지 않음- CSS background-image 속성에 Hero 이미지를 사용하지 않음
CSS 배경 이미지로 Hero 이미지를 꼭 사용해야 한다면 리소스 힌트인 preload를 사용해 일찍 다운받음
Hero 이미지와 함께 메인 텍스트도 의미 있는 콘텐츠를 구성함
- 따라서 폰트도 빨리 다운로드해야함
- 폰트는 페이지 로드 시간을 결정하는 핵심 리소스인데도 CSS의 font-face를 통해 로딩되므로 일반적으로 이미지들보다 다운로드 시작 시점이 늦음
- 따라서 이를 개선하려면 리소스 힌트인 preload를 사용하여 필요한 폰트를 일찌감치 다운로드하는 것을 권함
- 한글 폰트는 파일 크기가 매우 큼
- 따라서 preload 전에 폰트 파일을 경량화 해야 함
- 한글 폰트는 11172자 모두 사용하기 보다 KS X 1001 표준에서 지정한 2350자만 포함하도록 서브세트 폰트를 만들면 파일 크기를 훨씬 줄일 수 있음
- 웹 폰트 로딩 방식은 두 가지가 있음
- Flash Of Invisible Text, FOIT: 웹 폰트를 완전히 다운로드한 후 텍스트를 나타내는 방식
- Flash Of Unstyled Text, FOUT: 시스템 폰트를 먼저 사용 후 웹 폰트가 다운로드되면 대체하는 방식
- 사용자의 경험을 생각한다면 FOIT 방식보다 FOUT 방식을 사용하여 가능한 빠르게 사용자에게 메시지를 전달하는 것이 바람직함
- FOUT 방식을 사용하려면 CSS font-face 룰에서 font-display 속성을 swap으로 변경하면 됨
사용자 상호 작용 방해하지 않기
- 브라우저가 페이지를 시각적으로 완성했다 하더라도 버튼 클릭, 스크롤 등의 상호 작용이 원할하지 않으면 사용자들의 불만이 증가할 것임
- 따라서 사용자의 상호 작용을 측정하는 Time to Interactive나 First Input Delay 같은 지표가 웹 사이트 평판을 가늠하는 훌륭한 지표가 될 수 있음
- 구글의 Page Speed 점수도 Time to Interactive 지표에 가장 높은 가중치를 줌
- Time to Interactive 지표는 CPU 유휴 시간과 네트워크 사용량 등 클라이언트의 몇 가지 물리적 지표에 의하여 결정됨
- 그러므로 다운로드하는 리소스의 양과 수행 스크립트를 줄이는 것이 중요함
- 그런데 타사 리소스는 우리가 최적화하기 어려움
- 그러므로 도입 전 면밀한 검증, 도입 후 주기적인 점검, 사용이 완료되면 잊지 않고 제거하는 작업들이 필요함
- ReqestMap이나 Ghostery 같은 툴로 현재 웹 사이트에서 사용하고 있는 타사 리소스들의 현황을 파악할 수 있음
- 타사 제공 리소스들이 웹 사이트 성능에 영향을 주지 않게 하려면 그 리소스들을 호출하는 스크립트들이 비동기적으로 다운로드되어야 함
- 그렇지 않으면 단일 실패 지점(Single Point Of Failure, SPOF)가 발생할 수 있고, 만약 그 타사 호스트가 리소스 다운로드 요청에 응답하지 않으면 내 웹 사이트 로딩도 덩달아 지연되므로 피해가 발생할 수 있음
- 사용하는 타사 리소스가 이러한 잠재적 장애 요소를 가지고 있는지 SPOFO-Matic을 이용해 확인할 수 있음
💭 Insights
프로그래밍 인터페이스란?
- 프로그래밍 인터페이스는 프로그램과 특정 데이터 구조 또는 기능 사이의 통신을 가능하게 해주는 규칙과 메서드의 집합을 의미한다.
- 보통 Application Programming Interface 라고 한다. 즉 API를 의미하는 것이다.
- DOM과 CSSOM은 웹 브라우저에서 HTML과 CSS를 조작할 수 있도록 표준화된 API로 제공되며, 프로그래머가 자바스크립트를 통해 이를 조작할 수 있다.
- Document Object Model(DOM)은 Javacript에서 HTML 문서를 조작할 수 있는 API 집합
- CSS Object Model(CSSOM)은 JavaScript에서 CSS를 조작할 수 있는 API 집합
background-imgae 속성
책에서 아래와 같은 얘기가 나온다
첫 번째로 만약 그 이미지가 웹 사이트의 주요 이미지가 아니라면 CSS의 background-image 속성을 사용해 원하지 않는 다운로드를 피할 수 있음
브라우저가 CSS를 분석할 때 숨겨질 이미지는 미리 알고 다운로드하지 않기 때문임<img>
태그가 아닌 CSS의 background-image 속성을 이용하면 별도 설정 없이 브라우저가 알아서 CSS를 분석할 때 숨겨질 이미지는 미리 알고 다운로드하지 않는 것인가?
- background-image 속성은 DOM에 직접 참조되지 않고 CSS를 분석할 때 참조된다.
- DOM의 구조나 콘텐츠에 영향을 주지 않으므로, 렌더링에 반드시 필요하지 않다면 다운로드를 지연하거나 아예 생략할 수 있다.
- 예를 들어 CSS에서 display: none이나 visibility: hidden 속성을 사용한 요소에 적용된 background-image는 브라우저가 해당 이미지를 로드하지 않는다.
- 또한 브라우저는 화면(뷰포트)에 표시되지 않는 요소의 배경 이미지를 우선적으로 로드하지 않는다.
- 페이지 하단에 있는 배경 이미지는 사용자가 스크롤할 때까지 로드를 지연하거나 생략할 수 있다.
- 미디어 쿼리로 조건을 설정한 경우, 현재 활성화되지 않은 스타일에 정의된 background-image는 로드되지 않는다.
- 브라우저는 CSSOM을 생성하며 background-image를 렌더링과 관련된 보조 요소로 간주한다.
- 브라우저는 CSSOM 트리를 만들면서, 해당 요소가 화면에 표시될 가능성이 낮거나 숨겨진 상태라면 이미지 다운로드를 지연하거나 생략한다.
- background-image는 주요 콘텐츠가 아니여서 프리로더가 즉시 처리하지 않으며, 필요한 경우에만 로드한다.
- 보이지 않는 요소에 이미지를 강제로 로드하려면, background-image 대신
<img>
태그를 사용하거나 rel="preload"를 활용해야한다. - 따라서 중요한 콘텐츠가 아닌 보조적인 이미지를 처리할 때 background-image를 활용하면 성능 최적화에 유리하다.